package com.xust.oa.config;

import com.xust.oa.annotation.PassToken;
import com.xust.oa.annotation.adminPassToken;
import com.xust.oa.utils.JwtUtil;
import com.xust.oa.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @author zj
 * @time 2025/3/25 23:35
 */

@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String HEADER_NAME = "Access-Token";

    @Value("${config.redisTimeout}")
    private Long redisTimeout;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 判断是否需要拦截(通行证)
        if (isPassToken(handler)) return true;
        // 2. 获取请求体 token
        String token = request.getHeader(HEADER_NAME);
        //  3.解析 token  检查 token 是否过期/是否有效(弹到登录界面)
        if (!isTokenValid(token)) {
            unAuthorized(response, "Token is missing or invalid");
            return false;
        }
        // 4. 判断是否被管理员注解注解
        if (isAnnotatedWithAdminPassToken(handler)) {
            // 5. 获取当前用户身份并验证身份是否达标
            String role = JwtUtil.getUserRoleFromToken(token);
            if ("admin".equals(role)) {
                return true;
            } else {
                response.setStatus(HttpStatus.FORBIDDEN.value());
                return false;
            }
        }
        // 更新redis时间
        String id = JwtUtil.getUserIdFromToken(token);
        redisTemplate.expire("OAUser:token:" + id, redisTimeout, TimeUnit.SECONDS);
        return true;
    }
//    @Override
//    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
//
//    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 移除用户
        UserHolder.removeUser();
    }


    private boolean isPassToken(Object handler) {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        Class<?> clazz = handlerMethod.getBeanType();
        // 辅助方法：检查注解是否存在并且 required() 为 true
        if (checkAnnotation(PassToken.class, method) || checkAnnotation(PassToken.class, clazz)) {
            return true;
        }
        return false;
    }

    private boolean isAnnotatedWithAdminPassToken(Object handler) {
        if (!(handler instanceof HandlerMethod)) {
            return false;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        Class<?> clazz = handlerMethod.getBeanType();

        // 检查 AdminPassToken 注解（优先级最高）
        if (checkAnnotation(adminPassToken.class, method) || checkAnnotation(adminPassToken.class, clazz)) {
            return true;
        }

        return false;
    }

    private boolean checkAnnotation(Class<? extends Annotation> annotationClass, AnnotatedElement element) {
        if (element.isAnnotationPresent(annotationClass)) {
            Annotation annotation = element.getAnnotation(annotationClass);
            if (annotation.annotationType().equals(adminPassToken.class) ||
                    annotation.annotationType().equals(PassToken.class)) {
                return ((PassToken) annotation).required();
            }
        }
        return false;
    }





    private boolean isTokenValid(String token) {
        if (!StringUtils.hasText(token)) return false;
        String id = JwtUtil.getUserIdFromToken(token);
        String token2 = redisTemplate.opsForValue().get("OAUser:token:" + id);
        return token2 != null && token2.equals(token);
    }

    private void unAuthorized(HttpServletResponse response, String message) throws IOException {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        String errorMsg = String.format("{\"code\":401,\"msg\":\"%s\"}", message);
        response.getWriter().write(errorMsg);
    }
}
